#!/usr/bin/env python
# coding:utf-8
from aliyunsdkcore import client
import logging
import json
import time
from aliyunsdkcore.request import CommonRequest
from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S')


class AliEscScaling:
    """
    阿里云服务器通过弹性伸缩快速扩容返回扩容服务器对应IP
    需在阿里云配置弹性伸缩规则，并获取伸缩规则标识符
    """
    def __init__(self, access_key, secret, region_id="cn-shenzhen", instance_name="ess*"):
        """
        :param access_key: AccessKey ID
        :param secret: AccessKey Secret
        :param region_id: 地域ID
        :param instance_name: 实例名称，支持使用通配符*进行模糊搜索
        """
        self.instance_name = instance_name
        self.region_id = region_id
        self.end_time = None
        self.clt = client.AcsClient(access_key, secret, self.region_id)

    def list_instances(self):
        """
        获取主机列表
        :return:
        """
        request = DescribeInstancesRequest()
        request.set_InstanceName(self.instance_name)
        response = self._send_request(request)
        if response is not None:
            instance_list = response.get('Instances').get('Instance')
            return instance_list

    @staticmethod
    def _print_instance_id(item):
        """
        获取主机ID
        :param item:
        :return:
        """
        instance_id = item.get('InstanceId')
        return instance_id

    @staticmethod
    def _print_region_id(item):
        region_id = item.get("RegionId")
        return region_id

    @staticmethod
    def _print_create_time(item):
        """
        获取主机创建时间
        :param item:
        :return:
        """
        create_time = item.get("CreationTime")
        instance_id = item.get("InstanceId")
        vpc_ip = item.get("VpcAttributes").get("PrivateIpAddress").get("IpAddress")[0]
        public_ip = item.get("PublicIpAddress").get("IpAddress")[0]
        return dict(
            InstanceId=instance_id,
            CreationTime=create_time,
            vpc_ip=vpc_ip,
            public_ip=public_ip,
        )

    def _send_request(self, request):
        request.set_accept_format('json')
        try:
            response_str = self.clt.do_action(request)
            logging.info(response_str)
            response_detail = json.loads(response_str)
            return response_detail
        except Exception as e:
            logging.error(e)

    def exec_scaling_rule(self, scaling_rule_ari):
        """
        执行伸缩规则
        :param scaling_rule_ari: 伸缩规则标识符ScalingRuleAri
        :return:
        """
        request = CommonRequest()
        request.set_domain('ess.aliyuncs.com')
        request.set_method('POST')
        request.set_protocol_type('https')  # https | http
        request.set_version('2014-08-28')
        request.set_action_name('ExecuteScalingRule')

        request.add_query_param('RegionId', self.region_id)
        request.add_query_param('ScalingRuleAri',
                                scaling_rule_ari)

        response = self._send_request(request)
        if response is not None:
            logging.info(response)
            scaling_activity_id = response.get("ScalingActivityId", None)
            if scaling_activity_id:
                self.end_time = self.get_scaling_activity_detail(scaling_activity_id) - 3600
                scaling_host_list = self.list_instances()
                host_list = map(self._print_create_time, scaling_host_list)
                return map(self.get_now_scaling_host, host_list)
            logging.error(response.get("Message"))

    def get_scaling_activity_detail(self, sid):
        """
        获取伸缩活动执行结果
        :param sid:
        :return:
        """
        request = CommonRequest()
        request.set_domain('ess.aliyuncs.com')
        request.set_method('POST')
        request.set_protocol_type('https')  # https | http
        request.set_version('2014-08-28')
        request.set_action_name('DescribeScalingActivities')
        request.add_query_param('ScalingActivityId.1', sid)

        while True:
            response = self._send_request(request)
            if response is not None:
                scaling_activity = response.get("ScalingActivities").get("ScalingActivity")[0]
                if scaling_activity["StatusCode"] == 'InProgress':
                    time.sleep(3)
                    continue
                elif scaling_activity["StatusCode"] == 'Successful':
                    return self._utc_time(scaling_activity["EndTime"])
                else:
                    break
        logging.info(response)

    @staticmethod
    def _utc_time(date):
        return int(time.mktime(time.strptime(date, '%Y-%m-%dT%H:%MZ')))

    def get_now_scaling_host(self, host_create_time):
        """
        通过对比时间判断是否为本次伸缩节点
        :param host_create_time:
        :return:
        """
        create_time = self._utc_time(host_create_time.get("CreationTime"))
        if self.end_time <= create_time:
            return host_create_time


if __name__ == '__main__':
    scaling_rule_ari = 'ari:acs:xxxxx'
    aliyun_esc_scaling = AliEscScaling('xxxx', 'xxxx')
    data = aliyun_esc_scaling.exec_scaling_rule(scaling_rule_ari=scaling_rule_ari)
    logging.info(data)
